/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.meteocal.sessionbeans;

import it.polimi.meteocal.entities.Event;
import it.polimi.meteocal.entities.Invitation;
import it.polimi.meteocal.entities.Notification;
import it.polimi.meteocal.entities.User;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;


@Stateless
public class NotificationManager {

    @PersistenceContext
    EntityManager em;
    
    @EJB
    UserManager um;
    
    @Inject
    Principal principal;
    
    public void sendInvitation(Event e, List<User> invites){
        /* Inserimento della notification nel DB */
        List<Notification> allNotifications = em.createNamedQuery("Notification.findAll").getResultList();
        Iterator<Notification> it = allNotifications.iterator();
        boolean found = false;
        while(it.hasNext() && !found){
            Notification n = it.next();
            if(n.getType().equals("invitation") && n.getEventID().equals(e)){
                found = true;
                
            }
        }
        if(found == false){
            Date now = new Date();
            Notification n = new Notification(null, now, "invitation", null, e);
            em.persist(n);
        }
       
        /* Inserimento delle invitations nel DB */
        for(User u : invites){
            /* Refresh degli utenti invitati:
               merge viene fatta prima perché refresh lavora solo con entità managed, altrmenti
               avrei Exception: cannot refresh not managed object */
            em.refresh(em.merge(u)); 
            Integer cont = 0;
            for(Invitation inv : u.getInvitationList()){
                if(!inv.getEvent().equals(e)){
                    cont++;
                }
            }
            if(cont == u.getInvitationList().size()){
                Invitation i = new Invitation(u.getIdu(), e.getIde(), false);
                em.persist(i);
            }
        }
    }
    
    public void sendModificationNotification(Event e){
        /* Inserimento della notification nel DB */
        Date now = new Date();
        Notification n = new Notification(null, now, "modification", null, e);
        em.persist(n);
    }

    public void sendDeletionNotification(Event e) {
        /* Inserimento della notification nel DB */
        Date now = new Date();
        Notification n = new Notification(null, now, "deletion", null, e);
        em.persist(n);
    }
    
    public void sendNewDayNotification(Event e, Date proposedDate) {
        if(proposedDate != null){
            Date now = new Date();
            Notification n = new Notification(null, now, "newdayproposal", proposedDate, e);
            em.persist(n);
        }
    }

    public void sendBadWeatherNotification(Event e) {
        Date now = new Date();
        Notification n = new Notification(null, now, "badweather", null, e);
        em.persist(n);
    }    
    
    public List<Notification> getNotifications(){
        User logged = um.getLoggedUser();
        List<Notification> InvNotifications, ModifNotifications, DelNotifications,
                           NewDayNotifications, BadWeatherNotifications;
        
        /* Carico le notifiche di invito a evento */
        Query q1 = em.createQuery("SELECT n FROM User u, Invitation i, Event e, Notification n "
                                + "WHERE i.user=u AND i.event=e AND n.eventID=e AND "           // joins 
                                + "u.idu=:IDU AND e.valid='true' AND n.type='invitation'"); 
        InvNotifications = q1.setParameter("IDU", logged.getIdu()).getResultList();
        
        /* Carico le notifiche di modifica evento */
        Query q2 = em.createQuery("SELECT n FROM User u, Invitation i, Event e, Notification n "
                                + "WHERE i.user=u AND i.event=e AND n.eventID=e AND "           // joins 
                                + "u.idu=:IDU AND e.valid='true' AND i.participant='true' AND "
                                + "n.type='modification' AND n.date>i.acceptDate");
        ModifNotifications = q2.setParameter("IDU", logged.getIdu()).getResultList();  
         
        /* Carico le notifiche di cancellazione evento */
        Query q3 = em.createQuery("SELECT n FROM User u, Invitation i, Event e, Notification n "
                                + "WHERE i.user=u AND i.event=e AND n.eventID=e AND "           // joins 
                                + "u.idu=:IDU AND e.valid='false' AND i.participant='true' AND "
                                + "n.type='deletion' AND n.date>i.acceptDate");       
        DelNotifications = q3.setParameter("IDU", logged.getIdu()).getResultList();
        
        /* Carico le notifiche di proposta nuovo giorno */
        Query q4 = em.createQuery("SELECT n FROM Event e, Notification n "
                                + "WHERE n.eventID=e AND "                                      // joins
                                + "e.organizerID=:USER AND e.valid='true' AND "
                                + "n.type='newdayproposal'");
        NewDayNotifications = q4.setParameter("USER", logged).getResultList();
        
        /* Carico le notifiche di warning cattivo tempo */
        Query q5 = em.createQuery("SELECT DISTINCT n FROM Event e, Notification n, Invitation i "
                              + "WHERE n.eventID=e AND i.event=e AND "                        // joins
                              + "e.valid='true' AND i.participant='true' AND n.type='badweather' "
                              + "AND ((e.organizerID=:USER) OR (i.user=:USER AND n.date>i.acceptDate))");
        BadWeatherNotifications = q5.setParameter("USER", logged).getResultList();
           
        InvNotifications.addAll(ModifNotifications);
        InvNotifications.addAll(DelNotifications);
        InvNotifications.addAll(NewDayNotifications);
        InvNotifications.addAll(BadWeatherNotifications);
        List<Notification> allNotifications = this.sort(InvNotifications);
        return allNotifications;
    }
    
    public List<Notification> sort(List<Notification> x){
       List<Notification> result = new ArrayList<>();
       Iterator it;      
       Date maxDate;
       Notification n, nToAdd;
       Integer cont = 1, size = x.size();      
       while(cont <= size){
            maxDate = x.get(0).getDate();
            nToAdd = x.get(0);
            it = x.iterator();
            while(it.hasNext()){
                n = (Notification) it.next();
                if(n.getDate().after(maxDate)){
                    maxDate = n.getDate();
                    nToAdd = n; 
                }     
            }
            result.add(nToAdd);
            x.remove(nToAdd);           
            cont++;
       }
       return result;
    }
    
    public void setParticipation(Event e, boolean b){
         User logged = um.getLoggedUser();
         Iterator it = logged.getInvitationList().iterator();
         
         boolean found = false;
         Invitation i;
         while(it.hasNext() && !found){
             i = (Invitation) it.next();
             if(i.getEvent().equals(e)){
                 i.setParticipant(b);
                 i.setAcceptDate(new Date());
                 em.merge(i);
                 found = true;
             }           
         }       
    }
}
